gusucode.com > VC++ RingSDK界面库 > VC++ RingSDK界面库/code/libsrc/ringdows/ringdocksite.cpp
/********************************************************************** // // // ########## ###### ######### # ###### # // ############# ########### ######### ######### ### // ######## # ### ## ############# ## ## ##### # #### // #### ## ## ### ### ### # # ##### ##### // # ### # # ## ## ## ## ### // ## ###### ## ## #### #### # # ## // ######### ### ## ### ####### ###### ## ## ### // ###### ## ###### ## ## #### # ## #### // ####### ## ###### ## ### ## ## ### ###### // ######### ## ###### ## ###### ### ## ### # ##### // ## ###### ####### ### #### ## ## ####### ######## ## #### // ## #### ### # ### ### ## ########## ###### ## #### // ## ## ## ######### #### # ## // # ### // ## // ### // ## // // // 临风程序界面类库 ringdows.lib //作者:临风 // //版本:0.2 // //声明:本类库可以自由使用而不须对作者作出任何回报,但作者希望能得到 // 你的鼓励和支持。你可以对类库源码作出修改和改进,但希望你能在 // 修改的同时给作者一份同样的副本。 // 本类库不得用于任何商业用途,如确实需要,请与作者联系。 // //e-mail:ringphone@sina.com // //原文件名:ringctrlbar.cpp // //本文件说明: // 工具容纳窗口实现代码,该工具容纳窗口只是一个容器, // 容纳类似IE可移动的菜单栏及工具栏。 // 本窗口类位于父窗口四边,根据工具栏等自动调整尺寸及 // 隐藏/显示,所有操作自动完成,因此用户无须关心及调用 // 本类代码。 // // **********************************************************************/ #define MAKE_SELF_LIB #include "ringdows.h" LPRINGBARLINEINFO RingDockSite::m_EmptyLine = NULL; RingDockBar* RingDockSite::m_flybar = NULL; RingDockSite::RingDockSite(RingBaseWnd* parent,DWORD state/*=TBS_FLAG_DOCKTOP*/) { m_windowType = ITIS_DOCKSITE; SetParentObj(parent); SetAutoDelete(); m_SplitterSize = RING_SPLITERSIZE; RtlZeroMemory(&m_Background,sizeof(BARBMPINFO)); m_First = m_Curr = NULL; m_nChild = 0; m_CaptureBar = NULL; if(state > TBS_FLAG_DOCKRIGHT || state < TBS_FLAG_DOCKTOP) state = TBS_FLAG_DOCKTOP; m_State = state; RingWnd* temp = (RingWnd*)m_parent; temp->GetClientRect(&m_rcPos); RECT rc; ::GetClientRect(m_parent->Handle(),&rc); m_windowInfo.hCursor = LoadCursor(NULL,IDC_ARROW); switch(m_State) { case TBS_FLAG_DOCKTOP: m_rcPos.left = 0; m_rcPos.right = rc.right; m_rcPos.bottom = 0; m_cursor = LoadCursor(NULL,IDC_SIZENS); m_cursorLine = LoadCursor(NULL,IDC_SIZEWE); break; case TBS_FLAG_DOCKBOTTOM: m_rcPos.left = 0; m_rcPos.right = rc.right; m_rcPos.top = m_rcPos.bottom; m_cursor = LoadCursor(NULL,IDC_SIZENS); m_cursorLine = LoadCursor(NULL,IDC_SIZEWE); break; case TBS_FLAG_DOCKLEFT: m_rcPos.right = 0; m_cursor = LoadCursor(NULL,IDC_SIZEWE); m_cursorLine = LoadCursor(NULL,IDC_SIZENS); break; case TBS_FLAG_DOCKRIGHT: m_rcPos.left = m_rcPos.right; m_cursor = LoadCursor(NULL,IDC_SIZEWE); m_cursorLine = LoadCursor(NULL,IDC_SIZENS); break; } if(temp->m_dockSite) for(int i=0;i<4;i++) if(temp->m_dockSite[i] && temp->m_dockSite[i]->m_Background.hBrush) { //SetBgBmp(temp->m_dockSite[i]->m_Background.hbmp); m_Background = temp->m_dockSite[i]->m_Background; m_Background.bNeedDelete = FALSE; break; } } RingDockSite::~RingDockSite() { if(m_State != TBS_FLAG_DOCKTOP) m_pInterMenu = NULL; Free(); } //本函数必须由父窗口的CreateDockSite调用 HWND RingDockSite::Create() { /* WNDCLASSEX wndclsex = { sizeof(WNDCLASSEX), CS_DBLCLKS, InitWndProc, 0, 0, GetInstance(), NULL, NULL, NULL,//(HBRUSH)(COLOR_BTNFACE + 1), NULL, "RingDockSite", NULL }; RegRingdowClass(&wndclsex); */ if(!Register("RingDockSite", (HBRUSH)NULL, NULL, NULL, m_windowInfo.hCursor, NULL)) return NULL; if(m_Background.hBrush == NULL) { //m_Background.cx = m_Background.cy = 0; m_Background.hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); m_Background.bNeedDelete = TRUE; } CreateEx("","RingDockSite",WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);// | WS_VISIBLE); Show(); return m_hWnd; } void RingDockSite::Free() { if(m_Background.bNeedDelete) DeleteObject(m_Background.hBrush); LPRINGBARLINEINFO pre,tmp = m_First; RingDockBar* dockbar,*save; while(tmp) { dockbar = tmp->m_first; pre = tmp; tmp = tmp->m_nextline; while(dockbar) { save = dockbar->m_next; delete dockbar; dockbar = save; } Del(pre); } tmp = m_EmptyLine; m_EmptyLine = NULL; while(tmp) { pre = tmp; tmp = tmp->m_nextline; Del(pre); } } RingCoolMenu* RingDockSite::GetDockSiteMenu() { if(m_State == TBS_FLAG_DOCKTOP) { if(m_pInterMenu) return m_pInterMenu; m_pInterMenu = new RingCoolMenu; if(m_pInterMenu) m_pInterMenu->CreatePopup(); return m_pInterMenu; } else { RingDockSite* pSite = ((RingWnd*)m_parent)->CreateDockSite(TBS_FLAG_DOCKTOP); if(pSite) return pSite->GetDockSiteMenu(); } return NULL; } ////////////////////////////////////////////////////// // //设置画刷时如果原画刷需要销毁,则需要遍历其他DockSite, //因为其他DockSite也可能在使用该画刷 // ////////////////////////////////////////////////////// void RingDockSite::UpdateAllSiteBkg(HBRUSH hBrush) { RingWnd* temp = (RingWnd*)m_parent; if(temp->m_dockSite) { for(int i=0;i<4;i++) { if(temp->m_dockSite[i] && temp->m_dockSite[i]->m_Background.hBrush == hBrush) { RtlCopyMemory(&temp->m_dockSite[i]->m_Background,&m_Background,sizeof(BARBMPINFO)); temp->m_dockSite[i]->m_Background.bNeedDelete = FALSE; temp->m_dockSite[i]->UpdateBkg(); } } } } void RingDockSite::SetBgBmp(HBITMAP hbm,BOOL bSetOrg/*=FALSE*/) { if(hbm) { HBRUSH hBrush = m_Background.hBrush; GetBmpSize(hbm,(SIZE*)&m_Background); m_Background.hBrush = CreatePatternBrush(hbm); m_Background.bSetOrg = bSetOrg; if(m_Background.bNeedDelete) { UpdateAllSiteBkg(hBrush); DeleteObject(hBrush); } m_Background.bNeedDelete = FALSE; UpdateBkg(); } else SetBgColor(GetSysColor(COLOR_BTNFACE)); } void RingDockSite::SetBgBmp(LPCTSTR lpszBmp,BOOL bSetOrg/*=FALSE*/,HINSTANCE hInst/*=GetInstance()*/) { HBITMAP hbmp = NULL; if(lpszBmp) hbmp = LoadBitmap(hInst,lpszBmp); SetBgBmp(hbmp,bSetOrg); if(hbmp) { DeleteObject(hbmp); m_Background.bNeedDelete = TRUE; } } void RingDockSite::SetBgColor(COLORREF crColor) { HBRUSH hBrush = m_Background.hBrush; m_Background.cx = m_Background.cy = 0; m_Background.hBrush = CreateSolidBrush(crColor); m_Background.bSetOrg = FALSE; if(m_Background.bNeedDelete) { UpdateAllSiteBkg(hBrush); DeleteObject(hBrush); } m_Background.bNeedDelete = TRUE; UpdateBkg(); } LPRINGBARLINEINFO RingDockSite::GetEmptyLine() { if(m_EmptyLine) { LPRINGBARLINEINFO line = m_EmptyLine; m_EmptyLine = m_EmptyLine->m_nextline; memset(line,0,sizeof(RINGBARLINEINFO)); return line; } else return (LPRINGBARLINEINFO)New(sizeof(RINGBARLINEINFO)); } void RingDockSite::SetLineEmpty(LPRINGBARLINEINFO line) { if(line) { memset(line,0,sizeof(RINGBARLINEINFO)); line->m_nextline = m_EmptyLine; m_EmptyLine = line; } } void RingDockSite::RegFlyBar(RingDockBar* dockbar) { if(m_flybar == NULL) m_flybar = dockbar; else if(dockbar) { dockbar->m_next = m_flybar->m_next; m_flybar = dockbar; } } void RingDockSite::UnregFlyBar(RingDockBar* dockbar) { RingDockBar* bar = m_flybar,*prevbar = NULL; if(dockbar) { while(bar) { if(bar == dockbar) { if(prevbar == NULL) m_flybar = bar->m_next; else prevbar->m_next = bar->m_next; return; } prevbar = bar; bar = bar->m_next; } } } //判断鼠标是否在DockBar可移动边框内 RingDockBar* RingDockSite::CheckMouseInDockBar(RINGPARAMS& param) { LPRINGBARLINEINFO tmp = m_First; POINT pt = {param.mousept.x,param.mousept.y}; RingDockBar* dockbar; while(tmp) { if(tmp->isVisible) { dockbar = tmp->m_first; while(dockbar) { if(dockbar->IsVisible() && PtInRect(&dockbar->m_rcDockPos,pt)) return dockbar; dockbar = dockbar->m_next; } } tmp = tmp->m_nextline; } return NULL; } //判断鼠标是否在SizeBar移动边框内, //同时计算该移动框可移动的极限位置 BOOL RingDockSite::CheckMouseInSpliter(RINGPARAMS& param) { LPRINGBARLINEINFO tmp = m_First; POINT pt = {param.mousept.x,param.mousept.y}; BOOL bIn = FALSE; while(tmp) { if(tmp->isVisible && PtInRect(&tmp->m_SplitRc,pt))//tmp->m_SplitRc.bottom != 0) { bIn = TRUE; m_Curr = tmp; m_CaptureBar = NULL; SetCursor(m_cursor); RECT crc; ((RingWnd*)m_parent)->GetClientRect(&crc); switch(m_State) { case TBS_FLAG_DOCKTOP: m_ptLimit.x = tmp->m_SplitRc.top - tmp->m_maxSize + 10; m_ptLimit.y = crc.bottom; break; case TBS_FLAG_DOCKBOTTOM: m_ptLimit.x = crc.top - m_rcPos.top; m_ptLimit.y = tmp->m_SplitRc.bottom + tmp->m_maxSize - 10; break; case TBS_FLAG_DOCKLEFT: m_ptLimit.x = tmp->m_SplitRc.left - tmp->m_maxSize + 10; m_ptLimit.y = crc.right; break; case TBS_FLAG_DOCKRIGHT: m_ptLimit.x = crc.left - m_rcPos.left; m_ptLimit.y = tmp->m_SplitRc.right + tmp->m_maxSize - 10; break; } break; } tmp = tmp->m_nextline; } return bIn; } //处理拖动分隔栏 void RingDockSite::OnDragSpliter(RINGPARAMS& param) { //注意:param的鼠标坐标相对于本窗口, // m_rcPos,crc,rc坐标相对于父窗口, // m_dragger.GetCurrRect()坐标相对于屏幕 // 计算时必须统一坐标 RECT rc,crc; ((RingWnd*)m_parent)->GetClientRect(&crc); if(m_bSPLimited) { if(m_State > TBS_FLAG_DOCKBOTTOM) { if(param.mousept.x < m_ptLimit.x || param.mousept.x > m_ptLimit.y) { m_dragger.GetCurrRect(m_hWnd,&rc); m_dragger.SetPointX(rc.left); return; } } else { if(param.mousept.y < m_ptLimit.x || param.mousept.y > m_ptLimit.y) { m_dragger.GetCurrRect(m_hWnd,&rc); m_dragger.SetPointY(rc.top); return; } } } int ox = 0,oy = 0; LPRECT lprc = m_dragger.EraseRect(param.mousept.x,param.mousept.y,m_parent->Handle(),&rc); m_bSPLimited = TRUE; OffsetRect(&rc,-m_rcPos.left,-m_rcPos.top); switch(m_State) { case TBS_FLAG_DOCKTOP: ox = -rc.left; if(rc.bottom >= m_ptLimit.y) oy = max(m_ptLimit.y,10) - rc.bottom; else if(rc.top <= m_ptLimit.x) oy = m_ptLimit.x - rc.top; else m_bSPLimited = FALSE; break; case TBS_FLAG_DOCKBOTTOM: ox = -rc.left; if(rc.top <= m_ptLimit.x) oy = m_ptLimit.x - rc.top; else if(rc.bottom >= m_ptLimit.y) oy = m_ptLimit.y - rc.bottom; else m_bSPLimited = FALSE; break; case TBS_FLAG_DOCKLEFT: oy = -rc.top; if(rc.right > m_ptLimit.y) ox = max(m_ptLimit.y,10) - rc.right; else if(rc.left < m_ptLimit.x) ox = m_ptLimit.x - rc.left; else m_bSPLimited = FALSE; break; case TBS_FLAG_DOCKRIGHT: oy = -rc.top; if(rc.left <= m_ptLimit.x) ox = m_ptLimit.x - rc.left; else if(rc.right >= m_ptLimit.y) ox = m_ptLimit.y - rc.right; else m_bSPLimited = FALSE; break; } OffsetRect(lprc,ox,oy); m_dragger.DrawRect(4); } LRESULT RingDockSite::OnLButtonDbClk(RINGPARAMS& param) { RingDockBar* bar = CheckMouseInDockBar(param); if(bar) bar->DockBack(); return 0; } LRESULT RingDockSite::OnLButtonDown(RINGPARAMS& param) { m_bSPLimited = FALSE; if(CheckMouseInSpliter(param)) { if(m_ptLimit.y < m_ptLimit.x) m_ptLimit.y = m_ptLimit.x + 10; m_dragger.StartDrag(m_hWnd,param.mousept.x,param.mousept.y,&m_Curr->m_SplitRc,4); return 0; } else { m_CaptureBar = CheckMouseInDockBar(param); if(m_CaptureBar) return m_CaptureBar->StartDrag(m_hWnd,&m_dragger,param); } return 0; } LRESULT RingDockSite::OnMouseMove(RINGPARAMS& param) { if(m_CaptureBar) return m_CaptureBar->OnDrag(m_hWnd,&m_dragger,param); else if(m_dragger.IsDragging()) OnDragSpliter(param); else if(!CheckMouseInSpliter(param)) SetCursor(m_windowInfo.hCursor); return 0; } LRESULT RingDockSite::OnLButtonUp(RINGPARAMS& param) { SetCursor(m_windowInfo.hCursor); if(m_CaptureBar) { m_CaptureBar->StopDrag(m_parent->Handle(),&m_dragger,param); m_CaptureBar = NULL; } else if(m_dragger.IsDragging()) { int nStep; LPRECT lprc = m_dragger.StopDrag(m_hWnd,param.mousept.x,param.mousept.y); if(IsVert()) { nStep = lprc->left - m_Curr->m_SplitRc.left; if(m_State == TBS_FLAG_DOCKRIGHT) nStep = -nStep; else CopyRect(&m_Curr->m_SplitRc,lprc); } else { nStep = lprc->top - m_Curr->m_SplitRc.top; if(m_State == TBS_FLAG_DOCKBOTTOM) nStep = -nStep; else CopyRect(&m_Curr->m_SplitRc,lprc); } m_Curr->m_maxSize += nStep; UpdateLine(m_Curr,nStep); } return 0; } void RingDockSite::UpdateLine(LPRINGBARLINEINFO lpline,int nStep,BOOL bUpdate/*=TRUE*/) { //调整位于lpline后面的边线框位置 LPRINGBARLINEINFO tmp; //RingDockBar* bar; int lastpos = 0,step; if(lpline == NULL || lpline == m_First) { tmp = m_First; //检测调整线是否在最上或最左位置 //if(tmp && tmp->m_SplitRc.right != 0 && ((m_State & 1) == 1)) // lastpos = RING_SPLITERSIZE; } else { tmp = lpline; lastpos = tmp->m_pos; if(tmp && tmp->m_SplitRc.right != 0 && ((m_State & 1) == 1)) lastpos -= RING_SPLITERSIZE; } while(tmp) { step = lastpos - tmp->m_pos; tmp->m_pos = lastpos; if(tmp->m_SplitRc.right != 0) { //有分隔线且为下或右方停靠 if((m_State & 0x1) == 1)// && tmp != m_First) { step += RING_SPLITERSIZE; tmp->m_pos += RING_SPLITERSIZE; } lastpos += RING_SPLITERSIZE; if(IsVert()) OffsetRect(&tmp->m_SplitRc,step,0); else OffsetRect(&tmp->m_SplitRc,0,step); } lastpos += tmp->m_maxSize; tmp = tmp->m_nextline; } UpdatePos(nStep,bUpdate); } LRESULT RingDockSite::OnRButtonDown(RINGPARAMS& param) { RingMenu* rm = GetDockSiteMenu(); if(rm) rm->Popup(m_hWnd); return 0; } //刷新背景及刷新所有停靠窗口 void RingDockSite::UpdateBkg() { LPRINGBARLINEINFO tmp = m_First; RingDockBar* bar; InvalidateRect(m_hWnd,NULL,TRUE); while(tmp) { if(tmp->isVisible) { bar = tmp->m_first; while(bar) { if(bar->IsVisible() && bar->GetChild()) InvalidateRect(bar->GetChild()->Handle(),NULL,TRUE); bar = bar->m_next; } } tmp = tmp->m_nextline; } } void RingDockSite::DrawSite(HDC hDC,RINGPARAMS& param) { LPRINGBARLINEINFO tmp = m_First; RingDockBar* bar; //if(param.uMsg == WM_ERASEBKGND && !DrawBkg(hDC)) // DefaultProc(param); DrawBkg(hDC); if(m_State == TBS_FLAG_DOCKTOP && MASK_MATCH(m_parent->GetStyle(),WS_CAPTION) && tmp && tmp->isVisible) { //非底部且父窗口有标题栏,绘制最上一条横线 RECT rc = {0,0,m_rcPos.right,2}; DrawEdge(hDC,&rc,BDR_SUNKENOUTER,BF_TOP); DrawEdge(hDC,&rc,BDR_SUNKENOUTER,BF_BOTTOM); } while(tmp) { bar = tmp->m_first; while(bar) { //ExcludeClipRect(param.hdc,bar->m_rcClient.left,bar->m_rcClient.top, // bar->m_rcClient.right,bar->m_rcClient.bottom); if(!bar->Draw(hDC)) { OnDockBarHide(bar); bar->Show(bar->IsVisible()?SW_SHOW:SW_HIDE); return; } bar = bar->m_next; } if(tmp->isVisible && tmp->m_SplitRc.right != 0) { if(IsVert()) tmp->m_SplitRc.bottom = tmp->m_SplitRc.top + m_rcPos.bottom - m_rcPos.top; else tmp->m_SplitRc.right = tmp->m_SplitRc.left + m_rcPos.right - m_rcPos.left; DrawEdge(hDC,&tmp->m_SplitRc,BDR_RAISEDINNER,BF_RECT); DrawEdge(hDC,&tmp->m_SplitRc,BDR_RAISEDOUTER,BF_BOTTOMRIGHT); } tmp = tmp->m_nextline; } /*if(IsVert()) { RECT rc; GetClientRect(&rc); if(rc.right > 1) DrawEdge(hDC,&rc,BDR_SUNKENOUTER,BF_TOP); } */ } LRESULT RingDockSite::RingdowProc(HWND hWnd,RINGPARAMS param) { switch(param.uMsg) { case WM_CREATE: SetPos(m_rcPos.left,m_rcPos.top); SetCursor(m_windowInfo.hCursor); break; case WM_COMMAND: if(param.lParam != 0) return SendMessage(m_parent->Handle(),param.uMsg,param.wParam,param.lParam); else return OnDockBarHide(param.wParam); case RB_SETBKCOLOR: switch(param.wParam) { case RBIMG_HBITMAP: SetBgBmp((HBITMAP)param.lParam); return TRUE; case RBIMG_IDBMP: SetBgBmp((LPCTSTR)param.lParam); return TRUE; case RBIMG_BKCOLOR: SetBgColor(param.lParam); return TRUE; default: return 0; } case WM_MOVE: case WM_SIZE: InvalidateRect(m_hWnd,NULL,TRUE); return DefaultProc(param); case WM_LBUTTONDBLCLK: return OnLButtonDbClk(param); case WM_LBUTTONDOWN: return OnLButtonDown(param); case WM_LBUTTONUP: return OnLButtonUp(param); case WM_MOUSEMOVE: return OnMouseMove(param); case WM_RBUTTONDOWN: return OnRButtonDown(param); case WM_NCPAINT: return 0; case WM_ERASEBKGND: return TRUE; case WM_PAINT: { PAINTSTRUCT ps; DrawSite(BeginPaint(m_hWnd,&ps),param); EndPaint(m_hWnd,&ps); return 0; } case WM_NOTIFY: switch(param.lpnmhdr->code) { case TTN_NEEDTEXT: { ((LPTOOLTIPTEXT)param.lParam)->hinst = GetInstance(); return SendMessage(m_parent->Handle(),WM_RINGTOOLTIP,((LPTOOLTIPTEXT)param.lParam)->hdr.idFrom,param.lParam); } //case TBN_DROPDOWN: //工具栏DropDown按钮 // return SendMessage(param.lpnmhdr->hwndFrom,param); } if(IsWindowPtr(m_parent)) return SendMessage(m_parent->Handle(),param); return DefaultProc(param); case WM_CLOSE: Show(SW_HIDE); break; //case WM_WINDOWPOSCHANGED: // InvalidateRect(m_hWnd,NULL,FALSE); // return 0; case WM_MEASUREITEM: { RingCoolMenu* rm = GetDockMenu(); if(rm) rm->MeasureItem(param.lpmeasureitem); return SendMessage(m_parent->Handle(),param.uMsg,param.wParam,param.lParam); } case WM_DRAWITEM: { RingCoolMenu* rm = GetDockMenu(); if(rm) rm->Draw(param.lpdrawitem); return SendMessage(m_parent->Handle(),param.uMsg,param.wParam,param.lParam); } //case WM_EXITSIZEMOVE: // InvalidateRect(m_hWnd,NULL,TRUE); // break; default: { LRESULT res = CtlColorProc(hWnd,param); if(res != RM_NOTPROCESS) return res; else return RingWnd::DefaultProc(param); } } return 0; } BOOL RingDockSite::DrawBkg(HDC hDC,LPRECT lprc/*=NULL*/,LPSIZE lpoffset/*=NULL*/) { RECT rc,lrc={0,0,0,0}; SIZE offsz={0,0}; SIZE offsw={0,0}; if(lprc == NULL) { GetClientRect(&rc); lprc = &rc; } if(lpoffset == NULL) lpoffset = &offsz; if(m_Background.hBrush) { if(m_Background.bSetOrg) { if(m_Background.hStandWnd != (HWND)0xFFFFFFFF) { //计算背景相对偏移位置 GetWindowRect(m_hWnd,&lrc); MapWindowPoints(GetDesktopWindow(),m_Background.hStandWnd,(LPPOINT)&lrc,2); } SetBrushOrgEx(hDC,m_Background.cx - m_rcPos.left-lpoffset->cx-lrc.left, m_Background.cy - m_rcPos.top-lpoffset->cy-lrc.top,NULL); } /* int nDC = SaveDC(hDC); LPRINGBARLINEINFO tmp = m_First; RingDockBar* bar; while(tmp) { bar = tmp->m_first; while(bar) { ExcludeClipRect(hDC,bar->m_rcClient.left,bar->m_rcClient.top, bar->m_rcClient.right,bar->m_rcClient.bottom); bar = bar->m_next; } tmp = tmp->m_nextline; } */ FillRect(hDC,lprc,m_Background.hBrush); // RestoreDC(hDC,nDC); return TRUE; } else return FALSE; } //处理父窗口发来的消息,注意:hWnd是父窗口的HWND //这里有一些特别处理,必须上下的Docksite改变尺寸 //后才能改变左右的尺寸,由RingWnd确定更新顺序。 BOOL RingDockSite::OnParentNotify(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam) { switch(uMsg) { case WM_DOCKSITESIZECHANGE: //有DockSite尺寸变动,需要重新调整尺寸 case WM_SIZE: //父窗口改变尺寸 if(wParam != SIZE_MINIMIZED) return ParentReSize(LOWORD(lParam),HIWORD(lParam)); break; case WM_MOVE: { RingDockBar* dockbar = m_flybar; while(dockbar) { dockbar->UpdateFlyBkg(); dockbar = dockbar->m_next; } } } return FALSE; } BOOL RingDockSite::ParentReSize(int width,int height) { int nChk; if(IsVert()) { RingDockSite* tmp = ((RingWnd*)m_parent)->GetDockSite(TBS_FLAG_DOCKTOP); if(tmp) m_rcPos.top = tmp->m_rcPos.bottom; else m_rcPos.top = 0; tmp = ((RingWnd*)m_parent)->GetDockSite(TBS_FLAG_DOCKBOTTOM); if(tmp) m_rcPos.bottom = tmp->m_rcPos.top; else m_rcPos.bottom = height; if(m_State == TBS_FLAG_DOCKRIGHT) { m_rcPos.left = width - (m_rcPos.right - m_rcPos.left); m_rcPos.right = width; } //必须先调整尺寸,否则整行工具栏仍采用原尺寸为最大尺寸 nChk = MAKELONG(m_rcPos.left,m_rcPos.right); MoveWindow(m_hWnd,m_rcPos.left,m_rcPos.top,m_rcPos.right-m_rcPos.left,m_rcPos.bottom-m_rcPos.top,TRUE); AdjustChildrenV(m_rcPos.bottom-m_rcPos.top); //检查AdjustChildrenH是否调整了m_rcPos nChk = (nChk == MAKELONG(m_rcPos.left,m_rcPos.right)); } else { m_rcPos.right = width; if(m_State == TBS_FLAG_DOCKBOTTOM) { m_rcPos.top = height - (m_rcPos.bottom - m_rcPos.top); m_rcPos.bottom = height; } nChk = MAKELONG(m_rcPos.top,m_rcPos.bottom); //必须先调整尺寸,否则整行工具栏仍采用原尺寸为最大尺寸 MoveWindow(m_hWnd,m_rcPos.left,m_rcPos.top,m_rcPos.right-m_rcPos.left,m_rcPos.bottom-m_rcPos.top,TRUE); AdjustChildrenH(m_rcPos.right-m_rcPos.left); //检查AdjustChildrenH是否调整了m_rcPos nChk = (nChk == MAKELONG(m_rcPos.top,m_rcPos.bottom)); } if(nChk == 0) MoveWindow(m_hWnd,m_rcPos.left,m_rcPos.top,m_rcPos.right-m_rcPos.left,m_rcPos.bottom-m_rcPos.top,TRUE); return TRUE; } void RingDockSite::AdjustChildrenH(int nEdge) { LPRINGBARLINEINFO lpbarinfo = m_First,saveline; HDWP hdwp = BeginDeferWindowPos(10); int height = 0; if(m_State == TBS_FLAG_DOCKTOP) { height = 1; saveline = NULL; } else saveline = lpbarinfo; while(lpbarinfo) { if(saveline) { if(IsSizeBarInLine(saveline) && saveline->isVisible) { OffsetRect(&saveline->m_SplitRc,0,height - saveline->m_SplitRc.top); height += m_SplitterSize; } saveline = saveline->m_nextline; } else saveline = lpbarinfo; lpbarinfo->m_pos = height; hdwp = BarLineResizeH(hdwp,lpbarinfo,nEdge);//AdjustBarLineH(hdwp,nEdge,lpbarinfo,NULL); if(lpbarinfo->isVisible) height += lpbarinfo->m_maxSize; lpbarinfo = lpbarinfo->m_nextline; } if(IsSizeBarInLine(saveline) && saveline->isVisible) { OffsetRect(&saveline->m_SplitRc,0,height - saveline->m_SplitRc.top); height += m_SplitterSize; } if(hdwp) EndDeferWindowPos(hdwp); if(m_State == TBS_FLAG_DOCKTOP) m_rcPos.bottom = m_rcPos.top + height; else m_rcPos.top = m_rcPos.bottom - height; } void RingDockSite::AdjustChildrenV(int nEdge) { LPRINGBARLINEINFO lpbarinfo = m_First,saveline; HDWP hdwp = BeginDeferWindowPos(10); int width = 0; if(m_State == TBS_FLAG_DOCKLEFT) saveline = NULL; else saveline = lpbarinfo; while(lpbarinfo) { if(saveline) { if(IsSizeBarInLine(saveline) && saveline->isVisible) { OffsetRect(&saveline->m_SplitRc,width - saveline->m_SplitRc.left,0); width += m_SplitterSize; } saveline = saveline->m_nextline; } else saveline = lpbarinfo; lpbarinfo->m_pos = width; hdwp = BarLineResizeV(hdwp,lpbarinfo,nEdge);//AdjustBarLineH(hdwp,nEdge,lpbarinfo,NULL); if(lpbarinfo->isVisible) width += lpbarinfo->m_maxSize; lpbarinfo = lpbarinfo->m_nextline; } if(IsSizeBarInLine(saveline) && saveline->isVisible) { OffsetRect(&saveline->m_SplitRc,width - saveline->m_SplitRc.left,0); width += m_SplitterSize; } if(hdwp) EndDeferWindowPos(hdwp); m_rcPos.right = m_rcPos.left + width; } //窗口尺寸改变,需要调整子窗口位置 //本函数应该仅由OnParentNotify调用。主窗口改变尺寸调用OnParentNotify //改变本窗口尺寸。本窗口尺寸改变后调用本函数调整子窗口位置。 //本窗口只有两种情况改变尺寸: //父窗口改变尺寸,通过OnParentNotify通知;有SIZEBAR,用户鼠标 //拖动改变尺寸,这时通过鼠标按键放开的消息调用UpdatePos, //UpdatePos通过向父窗口发送WM_SIZE消息触发OnParentNotify, //这样可以调整所有CtrlBar。 void RingDockSite::NotifyChild(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { RingBaseWnd::NotifyChild(hWnd,uMsg,wParam,lParam); /* LPRINGBARLINEINFO tmp = m_First; RingDockBar* dockbar; while(tmp) { dockbar = tmp->m_first; while(dockbar) { dockbar->OnParentNotify(hWnd,uMsg,wParam,lParam); dockbar = dockbar->m_next; } tmp = tmp->m_nextline; } */ } //调整窗口尺寸,通过向父窗口发送WM_SIZE消息触发OnParentNotify, //这样可以调整所有CtrlBar。 void RingDockSite::UpdatePos(int nAddSize,BOOL bUpdate/*=TRUE*/) { switch(m_State) { case TBS_FLAG_DOCKBOTTOM: m_rcPos.top -= nAddSize; break; case TBS_FLAG_DOCKTOP: m_rcPos.bottom += nAddSize; break; case TBS_FLAG_DOCKRIGHT: m_rcPos.left -= nAddSize; break; case TBS_FLAG_DOCKLEFT: m_rcPos.right += nAddSize; break; } //如未调整尺寸,则不会刷新,需要手工刷新一下 InvalidateRect(m_hWnd,NULL,TRUE); if(bUpdate) UpdateAllSite(); } void RingDockSite::UpdateAllSite() { ((RingWnd*)m_parent)->UpdateDockSite(); } /************************************************** // //创建并加入停靠行信息 // 参数: // prev:前一行信息 // **************************************************/ LPRINGBARLINEINFO RingDockSite::AddLine(LPRINGBARLINEINFO prev) { LPRINGBARLINEINFO addline = GetEmptyLine(); if(addline) { addline->isVisible = TRUE; addline->m_maxSize = 0; addline->m_first = NULL; SetRectEmpty(&addline->m_SplitRc); if(prev == NULL) { //加到最前 prev = m_First; m_First = addline; addline->m_nextline = prev; addline->m_pos = 0; } else { addline->m_nextline = prev->m_nextline; prev->m_nextline = addline; addline->m_pos = prev->m_pos + prev->m_maxSize; if(prev->m_SplitRc.right != 0 && (m_State & 1) == 0) addline->m_pos += m_SplitterSize; } } return addline; } BOOL RingDockSite::UpdateSysMenu(RingDockBar* dockbar,LPCTSTR szText) { if(szText == NULL || *szText == '\0') return FALSE; BOOL bOK = FALSE; if(m_pInterMenu == NULL) m_pInterMenu = GetDockSiteMenu(); if(m_pInterMenu && !dockbar->IsMenuBar()) { bOK = m_pInterMenu->SetItemText(dockbar->GetId(),szText); if(!bOK) bOK = m_pInterMenu->Insert(dockbar->GetId(),m_pInterMenu->GetItemCount(),(LPSTR)szText,BY_POSITION); m_pInterMenu->CheckItem(dockbar->GetId(),dockbar->IsVisible()); } return bOK; } void RingDockSite::RemoveSysMenu(RingDockBar* dockbar) { if(m_pInterMenu && dockbar && !dockbar->IsMenuBar()) m_pInterMenu->Delete(dockbar->GetId()); } //响应菜单消息,隐藏/显示工具栏 BOOL RingDockSite::OnDockBarHide(UINT uId) { if(m_pInterMenu) { UINT uState = m_pInterMenu->GetItemCheckState(uId); if(uState != MF_ERRORS) { m_pInterMenu->CheckItem(uId,(uState==MF_UNCHECKED)); RingDockBar* dockbar = FindDockBar(uId); if(dockbar) dockbar->Show((uState==MF_UNCHECKED)?SW_SHOW:SW_HIDE); return TRUE; } } return FALSE; } void RingDockSite::OnDockBarHide(RingDockBar* dockbar) { if(m_pInterMenu && dockbar) m_pInterMenu->CheckItem(dockbar->GetId(),dockbar->IsVisible()?MF_CHECKED:MF_UNCHECKED); } RingDockBar* RingDockSite::GetDockBar(RingBaseWnd* wnd) { if(wnd == NULL) return NULL; LPRINGBARLINEINFO tmp = m_First; RingDockBar* dockbar; while(tmp) { dockbar = tmp->m_first; while(dockbar) if(dockbar->GetChild() == wnd) return dockbar; else dockbar = dockbar->m_next; tmp = tmp->m_nextline; } return NULL; } RingDockBar* RingDockSite::GetDockBar(UINT uDockBarId) { LPRINGBARLINEINFO tmp = m_First; RingDockBar* dockbar; while(tmp) { dockbar = tmp->m_first; while(dockbar) if(dockbar->GetId() == uDockBarId) return dockbar; else dockbar = dockbar->m_next; tmp = tmp->m_nextline; } return NULL; } RingDockBar* RingDockSite::FindDockBar(UINT uDockBarId) { RingDockSite *site; RingDockBar *dockbar = NULL; for(int i=0;i<4;i++) { site = ((RingWnd*)m_parent)->GetDockSite(i); if(site) { dockbar = site->GetDockBar(uDockBarId); if(dockbar) return dockbar; } } dockbar = m_flybar; while(dockbar) { if(dockbar->GetId() == uDockBarId) return dockbar; else dockbar = dockbar->m_next; } return NULL; } //创建或获取DockBar RingDockBar* RingDockSite::CreateDockBar(RingBaseWnd* wnd,BOOL bCanSize) { if(wnd == NULL) return NULL; RingDockBar* dockbar = NULL; //判断是否已有dockbar与wnd绑定,是为防止多次调用AddBar if(wnd->GetParent() == m_hWnd) dockbar = GetDockBar(wnd); else { //DockBar内的窗口其父窗口句柄为DockSite,但m_parent为原父窗口对象 RingBaseWnd* parent = GetWindowPtr(wnd->GetParent()); if(parent) { if(parent->GetWindowType() == ITIS_DOCKSITE) //已加入,但非停靠在本区域 dockbar = ((RingDockSite*)parent)->GetDockBar(wnd); else if(parent->GetWindowType() == ITIS_FLYBAR) dockbar = ((RingFlyBar*)parent)->GetDockBar(); } } if(dockbar == NULL) { //创建dockbar if(bCanSize) dockbar = new RingSizeBar; else { if(wnd->GetWindowType() == ITIS_MENUBAR) dockbar = new RingAllLineBar; else dockbar = new RingDockBar; } } return dockbar; } BOOL RingDockSite::ReleaseDockBar(RingBaseWnd* wnd) { RingDockBar* bar = GetDockBar(wnd); if(bar == NULL) { RingDockBar *prevbar = NULL; bar = m_flybar; while(bar) { if(bar->m_child && bar->m_child == wnd) { if(prevbar == NULL) m_flybar = bar->m_next; else prevbar->m_next = bar->m_next; break; } prevbar = bar; bar = bar->m_next; } } if(bar) { DelBar(bar); HWND hFlyWnd = wnd->GetParent(); wnd->SetParent(wnd->Parent()->Handle()); RemoveSysMenu(bar); if(bar->GetState() == TBS_FLAG_FLY) DestroyWindow(hFlyWnd); //flybar析构会销毁bar else delete bar; return TRUE; } return FALSE; } //加入停靠窗口,lprcPos为相对于父窗口坐标 RingDockBar* RingDockSite::AddBar(RingBaseWnd* wnd,LPCTSTR szTitle, UINT uDockStyle/*=TBS_EX_DOCKABLE*/, UINT uDockFlag/*=TBS_FLAG_DOCKTOP*/, LPRECT lprcPos/*=NULL*/, BOOL bCanSize/* = FALSE*/) { //创建或获取dockbar RingDockBar* dockbar = CreateDockBar(wnd,bCanSize); if(dockbar) { dockbar->SetDockStyle(uDockStyle); dockbar->SetDockTitle(szTitle); UpdateSysMenu(dockbar,dockbar->GetDockTitle()); if(dockbar->SetChild(wnd)) { //dockbar为新创建(未设置停靠窗口),更新尺寸 dockbar->UpdateSize(); } if(dockbar->GetDockSite() == NULL) dockbar->m_pSite = this; //无DockSite,必须设置 dockbar->Dockto(uDockFlag,lprcPos); } return dockbar; } ///////////////////////////////////////////////////////////// // //加入工具栏,工具栏必须是本窗口的子窗口且dockbar已调用SetDockSite加入到本停靠坞 //函数自动判断该工具栏是新加入或需要调整位置 //lprc为相对于父窗口坐标 // ///////////////////////////////////////////////////////////// BOOL RingDockSite::AddBar(RingDockBar* dockbar,LPRECT lprc) { if(dockbar && dockbar->m_pSite == this) { int m,nSize,nDel=0; LPRINGBARLINEINFO tmp = NULL; LPRINGBARLINEINFO lpline = NULL; BOOL bLast = FALSE; RECT rc; if(lprc) { CopyRect(&rc,lprc); MapWindowPoints(m_parent->Handle(),m_hWnd,(LPPOINT)&rc,2); lprc = &rc; //指定位置停靠,先根据lprc的中线判断停靠位置 if(IsVert()) { if(dockbar->IsAllLineBar()) { m = lprc->left; lprc = NULL; } else m = (lprc->left + lprc->right)/2; } else { if(dockbar->IsAllLineBar()) { m = lprc->top; lprc = NULL; } else m = (lprc->top + lprc->bottom)/2; } } else m = 9999; //加到最后 //寻找要停靠的行 lpline = GetDockLine(m); LPRINGBARLINEINFO save = dockbar->m_lineInfo; if(save) //已停靠在本窗口位置 { nDel = BarOutLine(dockbar,(lpline != save),tmp); if(tmp == NULL && lpline != save) { //要删除行 DelLine(save); } } nSize = AddBarInLine(dockbar,lpline,lprc); if(dockbar->IsSizeBar()) { if(lpline->m_nSizeBarCnt == 0) nSize += m_SplitterSize; lpline->m_nSizeBarCnt ++; if(lprc == NULL) //第一次加入 dockbar->InitDockSize(); SetSizeSplitRect(lpline); } UpdateLine(NULL,nSize + nDel); return TRUE; } else return FALSE; } LPRINGBARLINEINFO RingDockSite::GetDockLine(int nPos) { LPRINGBARLINEINFO tmp = m_First,prev = NULL,prev2 = NULL; if(tmp == NULL || nPos <= tmp->m_pos) return AddLine(NULL); while(tmp) { if(tmp->isVisible) { if(tmp->m_pos + tmp->m_maxSize > nPos) { //找到停靠行,判断是否独占行 if(tmp->m_first && tmp->m_first->IsAllLineBar())//(!tmp->m_first->CanDock(m_State) || tmp->m_first->IsAllLineBar())) { //独占行,停靠到新建行 if(nPos <= tmp->m_pos + tmp->m_maxSize/2 || tmp->m_first->IsStatusBar()) { //加到前面 return AddLine(prev); } else { //加到后面 return AddLine(tmp); } } else return tmp; } } prev2 = prev; prev = tmp; tmp = tmp->m_nextline; } if(prev && prev->m_first && prev->m_first->IsStatusBar()) return AddLine(prev2); else return AddLine(prev); } //在行内添加工具栏 int RingDockSite::AddBarInLine(RingDockBar* dockbar,LPRINGBARLINEINFO lpline,LPRECT lprc/*=NULL*/) { if(dockbar == NULL || lpline == NULL) return 0; RECT rc; if(lprc == NULL) lprc = &rc; dockbar->m_prev = dockbar->m_next = NULL; dockbar->m_lineInfo = lpline; if(IsVert()) { rc.left = lpline->m_pos; rc.right = rc.left + dockbar->m_rcDockPos.right - dockbar->m_rcDockPos.left; OffsetRect(lprc,lpline->m_pos - lprc->left,0); if(lpline->m_first == NULL) { rc.top = 0; rc.bottom = dockbar->m_rcDockPos.bottom - dockbar->m_rcDockPos.top; lpline->m_first = dockbar; RingDockSite* pSite = ((RingWnd*)m_parent)->GetDockSite(TBS_FLAG_DOCKBOTTOM); int nEdge; //工具栏有可能是从底部移过来,且底部DockSite有可能缩小高度,而此时本DockSite //的高度尚未变化,因此需依据底部DockSite尺寸判断 if(pSite) nEdge = pSite->m_rcPos.top; else nEdge = m_rcPos.bottom; if(lprc->bottom > m_rcPos.bottom) OffsetRect(lprc,0,nEdge - lprc->bottom); if(lprc->top < 0) OffsetRect(lprc,0,-lprc->top); dockbar->SetDockPos(lprc->left,lprc->top); rc.left = lpline->m_maxSize; lpline->m_maxSize = dockbar->m_nSize; InvalidateRect(m_hWnd,NULL,TRUE); return lpline->m_maxSize - rc.left; } else { rc.top = 9999; rc.bottom = 9999 + dockbar->m_rcDockPos.bottom - dockbar->m_rcDockPos.top; return AddBarInLineV(dockbar,lpline,lprc,(lprc->top + lprc->bottom)/2); } } else { rc.top = lpline->m_pos; rc.bottom = rc.top + dockbar->m_rcDockPos.bottom - dockbar->m_rcDockPos.top; OffsetRect(lprc,0,lpline->m_pos - lprc->top); if(lpline->m_first == NULL) { rc.left = 0; rc.right = dockbar->m_rcDockPos.right - dockbar->m_rcDockPos.left; lpline->m_first = dockbar; if(lprc->right > m_rcPos.right - m_rcPos.left) OffsetRect(lprc,m_rcPos.right - m_rcPos.left - lprc->right,0); if(lprc->left < 0) OffsetRect(lprc,-lprc->left,0); dockbar->SetDockPos(lprc->left,lprc->top); rc.left = lpline->m_maxSize; lpline->m_maxSize = dockbar->m_nSize; InvalidateRect(m_hWnd,NULL,TRUE); return lpline->m_maxSize - rc.left;//lpline->m_maxSize; } else { rc.left = 9999; rc.right = 9999 + dockbar->m_rcDockPos.right - dockbar->m_rcDockPos.left; return AddBarInLineH(dockbar,lpline,lprc,(lprc->left + lprc->right)/2); } } } //插入insbar到dockbar前面,仅插入,不作任何位置调整 void RingDockSite::InsertDockBar(LPRINGBARLINEINFO lpline,RingDockBar* insbar,RingDockBar* dockbar) { insbar->m_prev = dockbar->m_prev; insbar->m_next = dockbar; dockbar->m_prev = insbar; if(insbar->m_prev) insbar->m_prev->m_next = insbar; else lpline->m_first = insbar; } int RingDockSite::AddBarInLineV(RingDockBar* dockbar, LPRINGBARLINEINFO lpline, LPRECT lprc, int checkpos) { RingDockBar* bar = lpline->m_first,*save = NULL; while(bar) { if(lprc->top <= bar->m_rcDockPos.top || checkpos <= (bar->m_rcDockPos.top + bar->m_rcDockPos.bottom)/2) { //找到插入位置 InsertDockBar(lpline,dockbar,bar); save = NULL; break; } else { save = bar; bar = bar->m_next; } } if(save) { //未找到,save是最后一个工具栏 save->m_next = dockbar; dockbar->m_prev = save; dockbar->m_next = NULL; if(checkpos > 9999) //紧跟最后一个工具栏 OffsetRect(lprc,0,save->m_rcDockPos.bottom - lprc->top); } int nSize = dockbar->m_nSize - lpline->m_maxSize; lpline->m_maxSize = max(lpline->m_maxSize,dockbar->m_nSize); if(nSize > 0) { if(lpline->m_SplitRc.right != 0 && m_State == TBS_FLAG_DOCKLEFT) OffsetRect(&lpline->m_SplitRc,nSize,0); } if(lprc->top < 0) OffsetRect(lprc,0,-lprc->top); dockbar->OffsetDockPos(lprc->left-dockbar->m_rcDockPos.left,lprc->top-dockbar->m_rcDockPos.top); while(dockbar->m_next) { checkpos = dockbar->m_rcDockPos.bottom - dockbar->m_next->m_rcDockPos.top; if(checkpos > 0) { dockbar = dockbar->m_next; dockbar->OffsetDockPos(0,checkpos); } else break; } return max(0,nSize); } int RingDockSite::AddBarInLineH(RingDockBar* dockbar, LPRINGBARLINEINFO lpline, LPRECT lprc, int checkpos) { RingDockBar* bar = lpline->m_first,*save = NULL; while(bar) { if(lprc->left <= bar->m_rcDockPos.left || checkpos <= (bar->m_rcDockPos.left + bar->m_rcDockPos.right)/2) { //找到插入位置 InsertDockBar(lpline,dockbar,bar); save = NULL; break; } else { save = bar; bar = bar->m_next; } } if(save) { //未找到,save是最后一个工具栏 save->m_next = dockbar; dockbar->m_prev = save; dockbar->m_next = NULL; if(checkpos > 9999) //紧跟最后一个工具栏 OffsetRect(lprc,save->m_rcDockPos.right - lprc->left,0); } int nSize = dockbar->m_nSize - lpline->m_maxSize; lpline->m_maxSize = max(lpline->m_maxSize,dockbar->m_nSize); if(nSize > 0) { //lpline->m_maxSize += nSize; if(lpline->m_SplitRc.right != 0 && m_State == TBS_FLAG_DOCKTOP) OffsetRect(&lpline->m_SplitRc,0,nSize); } if(lprc->left < 0) OffsetRect(lprc,-lprc->left,0); dockbar->OffsetDockPos(lprc->left-dockbar->m_rcDockPos.left,lprc->top-dockbar->m_rcDockPos.top); while(dockbar->m_next) { checkpos = dockbar->m_rcDockPos.right - dockbar->m_next->m_rcDockPos.left; if(checkpos > 0) { dockbar = dockbar->m_next; dockbar->OffsetDockPos(checkpos,0); } else break; } //AdjustBarLineH(NULL,m_winpos.cx,lpline,dockbar,TRUE); return max(0,nSize); } //调整行内工具栏位置,dockbar如果非空,则表示优先满足该工具栏的位置 //nSize:DockSite的宽度 //int RingDockSite::AdjustBarLineH(HDWP hdwp,int nSize,LPRINGBARLINEINFO lpLine, // RingDockBar* dockbar,BOOL bCanWrap/*=FALSE*/) /* { if(lpLine && lpLine->m_first) { RingDockBar *bar = lpLine->m_first,*save = bar; int nSpace = 0,nPreSpace = 0; int nVSize = 0; int nTmp; if(dockbar == NULL) nTmp = nSize - ClientWidth(); else { if(dockbar->IsSizeBar()) nTmp = 0; else nTmp = -dockbar->m_winpos.cx; } int &nAddSpace = nTmp; while(bar && bar != dockbar) { save = bar; bar->AdjustChildH(nAddSpace); nPreSpace += bar->GetPreSpace(nAddSpace); nVSize = max(nVSize,bar->m_nSize); bar = bar->m_next; } if(dockbar == NULL) { //dockbar为NULL表示是调整父窗口尺寸时调用本函数,置为最后的工具栏 dockbar = save; nSpace = nPreSpace; } else nSpace = nPreSpace + dockbar->GetPreSpace(nAddSpace); if(nSpace < 0) { //空间不够,BAR需要后移 dockbar->OffsetDockPos(-nPreSpace,0); nPreSpace = 0; if(dockbar->m_winpos.x >= m_winpos.cx && bCanWrap) { nSpace = lpLine->m_maxSize; lpLine->m_maxSize = nVSize; return nVSize - nSpace + WrapLine(dockbar); } if(dockbar->m_winpos.right >= m_winpos.cx && bCanWrap && dockbar->m_next) { //无空间,后面的bar必须另起一行,WrapLine后dockbar->m_next为NULL nSpace = lpLine->m_maxSize; nVSize = max(nVSize,dockbar->m_nSize); lpLine->m_maxSize = nVSize; return nVSize - nSpace + WrapLine(dockbar->m_next); } } else nPreSpace = nSpace; //前面部分判断完毕 nVSize = max(nVSize,dockbar->m_nSize); save = dockbar; bar = dockbar->m_next; while(bar) { bar->AdjustChildH(nAddSpace); nSpace = bar->GetPreSpace(nAddSpace); nVSize = max(nVSize,bar->m_nSize); if(nSpace > 0) { //后面空间足够,到此为止 bar = save; break; } else { //与前面的BAR重叠,需要后移 bar->OffsetDockPos(-nSpace,0); save = bar; bar = bar->m_next; } } if(bar == NULL) bar = save; /* if(hdwp == NULL) { hdwp = BeginDeferWindowPos(10); bar->AdjustDockPosH(hdwp,m_winpos.right,nPreSpace,FALSE); EndDeferWindowPos(hdwp); InvalidateRect(m_hWnd,NULL,TRUE); } else bar->AdjustDockPosH(hdwp,m_winpos.right,nPreSpace,FALSE); */ /* nSpace = lpLine->m_maxSize; lpLine->m_maxSize = nVSize; return nVSize - nSpace; } return 0; } //*/ //工具栏一行中排不下时折行,bar是需要折行的第一个工具栏 int RingDockSite::WrapLine(RingDockBar* bar) { if(bar) { int *pos,x=0,y=0; int nSize = 0,nExtra = 0; LPRINGBARLINEINFO lpline = AddLine(bar->m_lineInfo); if(bar->m_prev) bar->m_prev->m_next = NULL; bar->m_prev = NULL; lpline->m_first = bar; if(IsVert()) { x = lpline->m_pos; pos = &y; } else { y = lpline->m_pos; pos = &x; } while(bar) { bar->m_lineInfo = lpline; bar->SetDockPos(x,y); if(bar->IsVisible()) { lpline->m_maxSize = max(lpline->m_maxSize,bar->m_nSize); if(IsVert()) *pos += (bar->m_rcDockPos.bottom - bar->m_rcDockPos.top); else *pos += (bar->m_rcDockPos.right - bar->m_rcDockPos.left); } bar = bar->m_next; } return lpline->m_maxSize; } return 0; } //删除工具栏 BOOL RingDockSite::DelBar(RingDockBar* dockbar,BOOL bUpdate/*=TRUE*/) { if(dockbar && dockbar->GetChild() && dockbar->GetChild()->GetParent() == m_hWnd) { LPRINGBARLINEINFO line = NULL,save = dockbar->m_lineInfo; int nSize = BarOutLine(dockbar,TRUE,line); //line作为引用,由BarOutLine设置 if(line == NULL) DelLine(save); UpdateLine(line,nSize,bUpdate); return TRUE; } return FALSE; } BOOL RingDockSite::HideBar(RingDockBar* dockbar) { if(dockbar == NULL) return FALSE; OnDockBarHide(dockbar); RingDockBar* bar = dockbar->m_lineInfo->m_first; while(bar) { if(bar->IsVisible()) return TRUE; bar = bar->m_next; } dockbar->m_lineInfo->isVisible = FALSE; int step = -dockbar->m_lineInfo->m_maxSize; UpdateLine(dockbar->m_lineInfo,-dockbar->m_lineInfo->m_maxSize); return TRUE; } //得到dockbar所在行的前一行。 //nPrevSize:前面行的总宽/高度。 LPRINGBARLINEINFO RingDockSite::GetPrevLine(LPRINGBARLINEINFO lpline) { if(m_First == lpline) return NULL; LPRINGBARLINEINFO tmp = m_First,prev = tmp; if(tmp) tmp = tmp->m_nextline; while(tmp) { if(tmp->isVisible) { if(tmp == lpline) return prev; } prev = tmp; tmp = tmp->m_nextline; } return prev; } //得到dockbar停靠行,仅在拖动工具栏判断使用。 //nPos:dockbar的中线位置,bLast:是否加到最后。 //返回:NULL-加到最前,非空-要加入的行,bLast=TRUE-加到最后,返回值为最后一行 /* LPRINGBARLINEINFO RingDockSite::GetDockLine(int nPos,BOOL &bLast) { LPRINGBARLINEINFO tmp = m_First,prev = NULL,prev2 = NULL; bLast = FALSE; if(tmp == NULL || nPos <= tmp->m_pos) return NULL; while(tmp) { if(tmp->isVisible) { if(tmp->m_pos + tmp->m_maxSize > nPos) { if(tmp->m_first && tmp->m_first->IsAllLineBar())//(!tmp->m_first->CanDock(m_State) || tmp->m_first->IsAllLineBar())) { //独占一行,停靠到新建行 if(nPos <= tmp->m_pos + tmp->m_maxSize/2 || tmp->m_first->IsStatusBar()) { //加到前面 if(prev) { tmp = GetEmptyLine(); tmp->m_nextline = prev->m_nextline; tmp->isVisible = TRUE; prev->m_nextline = tmp; return tmp; } else return NULL; } else { //加到后面 prev = GetEmptyLine(); prev->m_nextline = tmp->m_nextline; prev->isVisible = TRUE; tmp->m_nextline = prev; return prev; } } else return tmp; } } prev2 = prev; prev = tmp; tmp = tmp->m_nextline; } if(prev && prev->m_first && prev->m_first->IsStatusBar()) { if(prev2) { tmp = GetEmptyLine(); prev2->m_nextline = tmp; tmp->m_nextline = prev; tmp->isVisible = TRUE; return tmp; } else return NULL; } else { bLast = TRUE; return prev; } } */ //删除工具行 BOOL RingDockSite::DelLine(LPRINGBARLINEINFO lpline) { if(lpline) { LinkLine(GetPrevLine(lpline),lpline->m_nextline); SetLineEmpty(lpline); return TRUE; } return FALSE; } //工具栏从停靠行脱离,调用本函数须确保dockbar有效 int RingDockSite::BarOutLine(RingDockBar* dockbar,BOOL bCalcSize,LPRINGBARLINEINFO& line) { int nMax=0,nExtra=0; RingDockBar* bar = dockbar->m_lineInfo->m_first; if(bCalcSize) { //计算除要删除的工具栏外行的总高/宽度 while(bar) { if(bar != dockbar) { if(bar->IsVisible()) nMax = max(nMax,bar->m_nSize); } bar = bar->m_next; } } else nMax = dockbar->m_lineInfo->m_maxSize; line = dockbar->m_lineInfo; //连接前后工具栏 if(dockbar->m_next) dockbar->m_next->m_prev = dockbar->m_prev; if(dockbar->m_prev) dockbar->m_prev->m_next = dockbar->m_next; else line->m_first = dockbar->m_next; //设置行的总高/宽度 line->m_maxSize = nMax; if(dockbar->IsSizeBar()) { line->m_nSizeBarCnt --; if(line->m_nSizeBarCnt == 0) { nExtra = m_SplitterSize; //已无SizeBar,清空调整线信息 if(line->m_SplitRc.right != 0) SetRectEmpty(&line->m_SplitRc); } } //清空工具栏连接信息 dockbar->m_lineInfo = NULL; dockbar->m_prev = dockbar->m_next = NULL; if(line->m_first == NULL) //行内没有工具栏了,返回NULL line = NULL; if(line && nMax == 0) //其他工具栏是隐藏的 line->isVisible = FALSE; return min(0,nMax - dockbar->m_nSize - nExtra); } //连接两个barline,nPos:prev==NULL时根据nPos查找前一个barline void RingDockSite::LinkLine(LPRINGBARLINEINFO prev,LPRINGBARLINEINFO next) { if(prev) prev->m_nextline = next; else m_First = next; } BOOL RingDockSite::SetSizeSplitRect(LPRINGBARLINEINFO line) { if(line) { switch(m_State) { case TBS_FLAG_DOCKTOP: SetRect(&line->m_SplitRc,0,line->m_pos + line->m_maxSize,m_rcPos.right - m_rcPos.left, line->m_pos + line->m_maxSize + RING_SPLITERSIZE); break; case TBS_FLAG_DOCKBOTTOM: SetRect(&line->m_SplitRc,0,line->m_pos,m_rcPos.right - m_rcPos.left,line->m_pos + RING_SPLITERSIZE); break; case TBS_FLAG_DOCKLEFT: SetRect(&line->m_SplitRc,line->m_pos + line->m_maxSize,0, line->m_pos + line->m_maxSize + RING_SPLITERSIZE,m_rcPos.bottom - m_rcPos.top); break; case TBS_FLAG_DOCKRIGHT: SetRect(&line->m_SplitRc,line->m_pos,0,line->m_pos + RING_SPLITERSIZE,m_rcPos.bottom - m_rcPos.top); break; } return TRUE; } return FALSE; } HDWP RingDockSite::BarLineResizeH(HDWP hdwp,LPRINGBARLINEINFO lpLine,int nWidth) { if(lpLine && lpLine->m_first) { RingDockBar *bar = lpLine->m_first,*save = NULL; int nPreSpace = 0; int nFirstStep=0,nStep=0,nAddSpace = nWidth - Width(); if(lpLine->m_nSizeBarCnt > 0) { nStep = nAddSpace / lpLine->m_nSizeBarCnt; nFirstStep = nStep + (nAddSpace % lpLine->m_nSizeBarCnt); } else nFirstStep = nStep = nAddSpace; while(bar) { if(bar->IsVisible()) save = bar; bar->AdjustChildH(nFirstStep); nPreSpace += bar->GetPreSpace(); bar = bar->m_next; nFirstStep = nStep; } if(save) hdwp = save->AdjustDockPosH(hdwp,m_rcPos.right,nPreSpace,FALSE); else lpLine->isVisible = FALSE; } return hdwp; } HDWP RingDockSite::BarLineResizeV(HDWP hdwp,LPRINGBARLINEINFO lpLine,int nHeight) { if(lpLine && lpLine->m_first) { RingDockBar *bar = lpLine->m_first,*save = NULL; int nPreSpace = 0; int nFirstStep=0,nStep=0,nAddSpace = nHeight - Height(); if(lpLine->m_nSizeBarCnt > 0) { nStep = nAddSpace / lpLine->m_nSizeBarCnt; nFirstStep = nStep + (nAddSpace % lpLine->m_nSizeBarCnt); } else nFirstStep = nStep = nAddSpace; while(bar) { if(bar->IsVisible()) save = bar; bar->AdjustChildV(nFirstStep); nPreSpace += bar->GetPreSpace(); bar = bar->m_next; nFirstStep = nStep; } if(save) hdwp = save->AdjustDockPosV(hdwp,nHeight/*m_winpos.bottom*/,nPreSpace,FALSE); else lpLine->isVisible = FALSE; } return hdwp; } /* BOOL RingDockSite::NeedDrawDivider(RingDockBar* dockbar) { if(m_State == TBS_FLAG_DOCKTOP && m_First && m_First->m_first == dockbar) return TRUE; else return FALSE; } /* int RingDockSite::AdjustBarLineV(RingDockBar* bar,int nSpace,RingDockBar* dockbar,int& nSize) { if(bar) { int nAdd = 0,space = 0; nSize = max(nSize,bar->m_nSize); if(bar->m_prev) { //前面有工具栏,判断前面总可移动空间 space = bar->m_winpos.y - (bar->m_prev->m_winpos.y + bar->m_prev->m_winpos.cy); if(space < 0) { //两者重叠 if(bar == dockbar) { //以dockbar为准,前面的工具栏前移 space = nSpace + space; nSpace = max(0,space); space = min(0,space); } bar->m_winpos.y -= space; space = 0; } nSpace += space; } space = nSpace + m_winpos.cy - (bar->m_winpos.y + bar->m_winpos.cy); if(space <= 0) { //最后的bar,后面的bar必须另起一行 bar->SetDockPos(bar->m_winpos.x,bar->m_winpos.y - nSpace); bar->m_lineInfo->m_maxSize = nSize; nSize += WrapLine(bar->m_next); return bar->m_winpos.y; } if(bar->m_next == NULL) { //最后的bar,必须返回 if(space >= nSpace) space = 0; else space = nSpace - space; //bar->SetPos(bar->m_winpos.x,bar->m_winpos.y - space); //return bar->m_winpos.y; } else { //还有空间 space = (bar->m_winpos.y + bar->m_winpos.cy) - AdjustBarLineV(bar->m_next,nSpace,dockbar,nSize); if(space < 0) space = 0; } bar->SetDockPos(bar->m_winpos.x,bar->m_winpos.y - space); return bar->m_winpos.y; } return 9999; } */